package server.loader;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import server.mapper.Context;
import server.mapper.Host;
import server.servlet.ServletDefinition;
import servlet.HttpServlet;

import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by louisyuu on 2020/4/2 上午11:07
 */


public class ServletLoader {

    public final static Map<String, HttpServlet> servletMap = new HashMap<>();


    public final static Map<String, ServletDefinition> servletDefinitionMap = new HashMap<>();


    /**
     * 加载web.xml
     *
     * @param webXmlPath
     */
    public void resolveWebXml(String webXmlPath, Context context) {
        InputStream resourceAsStream = ServletLoader.class.getClassLoader().getResourceAsStream(webXmlPath);
        SAXReader saxReader = new SAXReader();

        try {
            Document document = saxReader.read(resourceAsStream);
            Element rootElement = document.getRootElement();

            List<Element> selectNodes = rootElement.selectNodes("//servlet");
            for (int i = 0; i < selectNodes.size(); i++) {
                Element element = selectNodes.get(i);
                // <servlet-name>lagou</servlet-name>
                Element servletNameElement = (Element) element.selectSingleNode("servlet-name");
                String servletName = servletNameElement.getStringValue();
                // <servlet-class>server.LagouServlet</servlet-class>
                Element servletClassElement = (Element) element.selectSingleNode("servlet-class");
                String servletClass = servletClassElement.getStringValue();


                // 根据servlet-name的值找到url-pattern
                Element servletMapping = (Element) rootElement.selectSingleNode("/web-app/servlet-mapping[servlet-name='" + servletName + "']");
                // /lagou
                String urlPattern = servletMapping.selectSingleNode("url-pattern").getStringValue();

                if (context != null) {
                    urlPattern = context.getPath() + urlPattern;
                }
                servletDefinitionMap.put(urlPattern, new ServletDefinition(servletName, urlPattern, servletClass, context));
            }


        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 初始化本地Servlet
     */
    public void loadLocalServlet() {
        resolveWebXml("web.xml", null);


        servletDefinitionMap.forEach((k, v) -> {
            try {
                if (v.getContext() == null) {
                    servletMap.put(k, (HttpServlet) Class.forName(v.getServletClassName()).newInstance());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        });


    }


    /**
     * Servlet
     */
    public void loadWebAppServlets() {
        Host host = Host.hostMap.get("localhost");

        for (Context context : host.getContexts()) {
            WebAppsClassLoader webAppsClassLoader = new WebAppsClassLoader(host, context.getDocBase());

            // webapps/web-demo-one/WEB-INF/web.xml

            String webXmlPath = webAppsClassLoader.getWebAppsWebInfPath() + "/web.xml";

            resolveWebXml(webXmlPath, context);

        }


        servletDefinitionMap.forEach((k, v) -> {
            try {
                if (v.getContext() != null) {
                    WebAppsClassLoader webAppsClassLoader = new WebAppsClassLoader(host, v.getContext().getDocBase());
                    servletMap.put(k, (HttpServlet) webAppsClassLoader.loadClass(v.getServletClassName()).newInstance());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        });


    }





    /**
     * Servlet
     */
    public void loadWebAppServletsUseParentsDelegation() {
        Host host = Host.hostMap.get("localhost");

        for (Context context : host.getContexts()) {
            WebAppsClassLoader webAppsClassLoader = new WebAppsClassLoader(host, context.getDocBase());

            // webapps/web-demo-one/WEB-INF/web.xml

            String webXmlPath = webAppsClassLoader.getWebAppsWebInfPath() + "/web.xml";

            resolveWebXml(webXmlPath, context);

        }


        servletDefinitionMap.forEach((k, v) -> {
            try {
                if (v.getContext() != null) {
                    WebAppsClassLoader webAppsClassLoader = new WebAppsClassLoader(host, v.getContext().getDocBase());
                    servletMap.put(k, (HttpServlet) webAppsClassLoader.loadClassUseParentsDelegationModel(v.getServletClassName()).newInstance());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        });


    }


}
